﻿#pragma warning disable 1690

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels;

using IVisual;

namespace Config_App
{
    /// <summary>
    /// Hauptform
    /// </summary>
    public partial class frm_Main : Form
    {
        private TcpClientChannel channel;

        private bool[,] _EinG_M;
        private I_config _cfg;

        private BackgroundWorker _AutoDiscovery_cli;
        private IVisual._SC.AutoDiscovery.cls_AutoDiscovery_Client svcAutoDiscoveryClient;

        public frm_Main()
        {
            InitializeComponent();

            IVisual._SC.cls_LOG.LOG_LEVEL = IVisual._SC.cls_LOG.LOGLEVEL.INFO;

            try
            {
                int ind = Array.FindIndex(Environment.GetCommandLineArgs(), delegate(string s) { return s.Contains("-LOGLEVEL="); });
                if (ind >= 0)
                    IVisual._SC.cls_LOG.LOG_LEVEL = (IVisual._SC.cls_LOG.LOGLEVEL)Convert.ToInt32(Environment.GetCommandLineArgs()[ind].Replace("-LOGLEVEL=", ""));

                IVisual._SC.cls_LOG.HTML = !(Array.FindIndex(Environment.GetCommandLineArgs(), delegate(string s) { return s.Contains("-NOHTML"); }) >= 0);
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
                this.Close();
            }
        }

        private void frm_main_Load(object sender, EventArgs e)
        {
            //Versuche dei Verbindung zum Dienst herzustellen
            try
            {
                IVisual._SC.frm_Connect _frm_con = new IVisual._SC.frm_Connect(!Environment.GetCommandLineArgs().Contains("-NOAD"));
                if (_frm_con.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    CONNECT(_frm_con.IP.ToString(), _frm_con.Port);
                else
                    throw new Exception("Abbrechen geklickt");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                this.Close();
                return;
            }

            this._cb_AF.SelectedIndex = 0;

            //Lade configuration vom Dienst
            LOAD_CFG(_cfg.GET_CFG());
        }

        /// <summary>
        /// Handelt den Verbindungsaufbau
        /// </summary>
        /// <param name="IP">Ziel-IP</param>
        /// <param name="port">Ziel-Port</param>
        private void CONNECT(string IP, long port)
        {
            channel = new TcpClientChannel();
            ChannelServices.RegisterChannel(channel, true);

            _cfg = (I_config)Activator.GetObject
            (
                typeof(I_config),
                "tcp://" + IP + ":" + port + "/_RM_Neuro_Config"
            );
        }

        /// <summary>
        /// Lädt die koplette Konfiguration aus dem Objekt
        /// </summary>
        /// <param name="_cfg">zu ladente Config</param>
        private void LOAD_CFG(I_config _cfg)
        {
            IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.METHOD_INVOKE, "start");

            try
            {
                // Laden auch wenn ggf. unnötig
                this._uc_APPROX.input = _cfg._I;
                this._uc_APPROX.output = _cfg._O;
                this._uc_APPROX.data = _cfg.Object_Cache.Ap_data;

                // Laden auch wenn ggf. unnötig
                this._uc_TIMESERIES.data = _cfg.Object_Cache.TS_data;
                this._uc_TIMESERIES.windowSize = _cfg.Object_Cache.TS_windowSize;
                this._uc_TIMESERIES.predictionSize = _cfg.Object_Cache.TS_predictionSize;

                this._EinG_M = _cfg.Object_Cache.EinG_M;

                //für remote-debugging
                if (System.Diagnostics.Debugger.IsAttached)
                    System.Diagnostics.Debugger.Break();

                switch (_cfg.mode)
                {
                    case "Logic":
                        this._tc_main.SelectedIndex = 0;
                        this._dgv_vakuetable.Columns.Clear();

                        // Anhand der eingabepattern die Spalten rekonstruiren (I)
                        for (int i = 0; i < _cfg._I[0].GetLength(0); i++)
                        {
                            DataGridViewCheckBoxColumn CB_COL;
                            CB_COL = new DataGridViewCheckBoxColumn();
                            CB_COL.HeaderText = "IN " + (i + 1);
                            CB_COL.Name = "I" + (i + 1);
                            CB_COL.AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;
                            this._dgv_vakuetable.Columns.Add(CB_COL);
                        }

                        // Anhand der eingabepattern die Spalten rekonstruiren (O)
                        for (int i = 0; i < _cfg._O[0].GetLength(0); i++)
                        {
                            DataGridViewCheckBoxColumn CB_COL;
                            CB_COL = new DataGridViewCheckBoxColumn();
                            CB_COL.HeaderText = "OUT " + (i + 1);
                            CB_COL.Name = "O" + (i + 1);
                            CB_COL.AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;
                            this._dgv_vakuetable.Columns.Add(CB_COL);
                        }

                        // Werte setzten, aus der cfg
                        for (int i = 0; i < _cfg._I.GetLength(0); i++)
                        {
                            int IN_len = _cfg._I[0].GetLength(0);

                            object[] _vals = new object[this._dgv_vakuetable.Columns.Count];
                            for (int n = 0; n < IN_len; n++)
                                _vals[n] = _cfg._I[i][n] == 1;
                            for (int n = 0; n < _cfg._O[0].GetLength(0); n++)
                                _vals[IN_len + n] = _cfg._O[i][n] == 1;

                            this._dgv_vakuetable.Rows.Add(_vals);
                        }
                        break;

                    case "Approximation":
                        this._tc_main.SelectedIndex = 1;
                        // Werte wurden oben bereits gesesetzt, also anwenden
                        this._uc_APPROX.UpdateDataListView();
                        break;

                    case "TimeSeries":
                        this._tc_main.SelectedIndex = 2;
                        // Werte wurden oben bereits gesesetzt, also anwenden
                        this._uc_TIMESERIES.UPDATE_ALL_DATA();
                        break;

                    case "Zeichenerkennung":
                        this._tc_main.SelectedIndex = 3;
                        // Da object_cache, besser später anwenden
                        this._uc_OCR.regularFonts = _cfg.Object_Cache.OCR_regularFonts;
                        this._uc_OCR.italicFonts = _cfg.Object_Cache.OCR_italicFonts;
                        this._uc_OCR.initialReceptorsCount = _cfg.Object_Cache.OCR_initialReceptorsCount;
                        this._uc_OCR.receptorsCount = _cfg.Object_Cache.OCR_receptorsCount;
                        this._uc_OCR.receptors = _cfg.Object_Cache.OCR_Receptors;
                        // Werte wurden oben bereits gesesetzt, also anwenden
                        this._uc_OCR.UPDATE_ALL_DATA();
                        break;

                    case "Datendateien":
                        this._tc_main.SelectedIndex = 4;
                        //DGVs laden
                        this._uc_CSV._DATA = _cfg.Object_Cache.DD_DATA;
                        this._uc_CSV._COLS = _cfg.Object_Cache.DD_COLS;
                        break;

                }

                // Netzdimensions-LV rekonstruieren
                this._lv_Netzdimension.Items.Clear();
                for (int i = 0; i < _cfg._size.GetLength(0) - 1; i++)
                    this._lv_Netzdimension.Items.Add(_cfg._size[i].ToString());

                //Andere Paremeter setzten
                this._nud_ll.Value = (decimal)_cfg.learningLimit;
                this._nud_LR.Value = (decimal)_cfg.learningRate;
                this._nud_mom.Value = (decimal)_cfg.momentum;
                this._cb_s2.Checked = _cfg.S2;
                this._nud_ll2.Value = (decimal)_cfg.learningLimit2;
                this._nud_LR2.Value = (decimal)_cfg.learningRate2;
                this._nud_mom2.Value = (decimal)_cfg.momentum2;
                this._nud_alpha.Value = (decimal)_cfg.alpha;
                this._cb_cycles.Checked = _cfg.zyklenabbruch;
                this._cb_rean.Checked = _cfg.RESTART;

                this._cb_MAIL_Enabled.Checked = _cfg.MAIL_Enabled;
                this._tb_MAIL_From.Text = _cfg.MAIL_FROM;
                this._tb_MAIL_To.Text = _cfg.MAIL_TO;
                this._nud_MAIL_Port.Value = _cfg.MAIL_Port;
                this._tb_EMAIL_Host.Text = _cfg.MAIL_Host;
                this._tb_MAIL_Betreff.Text = _cfg.MAIL_Betreff;
                this._cb_MAIL_Auth.Checked = _cfg.MAIL_Auth;
                this._tb_MAIL_USN.Text = _cfg.MAIL_USN;
                this._tb_MAIL_PW.Text = _cfg.MAIL_PW;

                this._tb_visu_IP.Text = _cfg.Visual_IP;
                this._tb_visual_port.Text = _cfg.Visual_Port.ToString();

                this._cb_AF.SelectedIndex = (int)_cfg.AF - 1;
            }catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.METHOD_INVOKE, "ende");
        }

        /// <summary>
        /// Prüft ob wirklich eine Zahl in die LV eingeben wurde ;-)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _lv_Netzdimension_AfterLabelEdit(object sender, LabelEditEventArgs e)
        {
            try
            {
                Convert.ToInt32(e.Label);
            }
            catch (Exception)
            {
                e.CancelEdit = true;
            }
        }

        // Wendet die Konfiguration an
        private void _cmd_apply_Click(object sender, EventArgs e)
        {
            // für die Remote-debugging
            if (System.Diagnostics.Debugger.IsAttached)
                System.Diagnostics.Debugger.Break();

            try
            {
                // Für jede Option, die entsprechende Parameter setzen
                switch (this._tc_main.SelectedTab.Text)
                {
                    case "Logic":
                        _cfg._I = ValueTable("I");
                        _cfg._O = ValueTable("O");
                        break;
                    case "Approximation":
                        _cfg._I = this._uc_APPROX.input;
                        _cfg._O = this._uc_APPROX.output;
                        _cfg.Object_Cache.Ap_data = this._uc_APPROX.data;
                        break;
                    case "TimeSeries":
                        _cfg._I = this._uc_TIMESERIES.input;
                        _cfg._O = this._uc_TIMESERIES.output;
                        _cfg.Object_Cache.TS_data = this._uc_TIMESERIES.data;
                        _cfg.Object_Cache.TS_windowSize = this._uc_TIMESERIES.windowSize;
                        _cfg.Object_Cache.TS_predictionSize = this._uc_TIMESERIES.predictionSize;
                        break;
                    case "Zeichenerkennung":
                        _cfg._I = this._uc_OCR.input;
                        _cfg._O = this._uc_OCR.output;
                        _cfg.Object_Cache.OCR_Receptors = this._uc_OCR.receptors;
                        _cfg.Object_Cache.OCR_initialReceptorsCount = this._uc_OCR.initialReceptorsCount;
                        _cfg.Object_Cache.OCR_italicFonts = this._uc_OCR.italicFonts;
                        _cfg.Object_Cache.OCR_receptorsCount = this._uc_OCR.receptorsCount;
                        _cfg.Object_Cache.OCR_regularFonts = this._uc_OCR.regularFonts;
                        break;
                    case "Datendateien":
                        _cfg._I = this._uc_CSV._I;
                        _cfg._O = this._uc_CSV._O;
                        _cfg.Object_Cache.DD_DATA = this._uc_CSV._DATA;
                        _cfg.Object_Cache.DD_COLS = this._uc_CSV._COLS;
                        break;
                }

                // Grundsätzliche Parameter übernhemen
                _cfg.mode = this._tc_main.SelectedTab.Text;

                int[] _size = new int[this._lv_Netzdimension.Items.Count + 1];
                for (int i = 0; i < this._lv_Netzdimension.Items.Count; i++)
                    _size[i] = Convert.ToInt32(this._lv_Netzdimension.Items[i].Text);
                _size[_size.Length - 1] = _cfg._O[0].GetLength(0);
                _cfg._size = _size;

                _cfg.Input_Count = _cfg._I[0].GetLength(0);
                _cfg.learningLimit = (float)this._nud_ll.Value;
                _cfg.learningRate = (float)this._nud_LR.Value;
                _cfg.momentum = (float)this._nud_mom.Value;
                _cfg.S2 = this._cb_s2.Checked;
                _cfg.learningLimit2 = (float)this._nud_ll2.Value;
                _cfg.learningRate2 = (float)this._nud_LR2.Value;
                _cfg.momentum2 = (float)this._nud_mom2.Value;
                _cfg.alpha = (float)this._nud_alpha.Value;
                _cfg.zyklenabbruch = this._cb_cycles.Checked;
                _cfg.RESTART = this._cb_rean.Checked;
                _cfg.AF = (IVisual.I_AF.Aktivierungsfunktion)(this._cb_AF.SelectedIndex + 1);

                _cfg.Visual_IP = IVisual._SC.cls_tools.try_resolve(this._tb_visu_IP.Text).ToString();
                _cfg.Visual_Port = Convert.ToInt32(this._tb_visual_port.Text);

                _cfg.MAIL_Enabled = this._cb_MAIL_Enabled.Checked;
                _cfg.MAIL_FROM = this._tb_MAIL_From.Text;
                _cfg.MAIL_TO = this._tb_MAIL_To.Text;
                _cfg.MAIL_Port = (int)this._nud_MAIL_Port.Value;
                _cfg.MAIL_Host = this._tb_EMAIL_Host.Text;
                _cfg.MAIL_Betreff = this._tb_MAIL_Betreff.Text;
                _cfg.MAIL_Auth = this._cb_MAIL_Auth.Checked;
                _cfg.MAIL_USN = this._tb_MAIL_USN.Text;
                _cfg.MAIL_PW = this._tb_MAIL_PW.Text;

                _cfg.Object_Cache.EinG_M = this._EinG_M;

                // Configuration ins remoting schreiben
                if (!_cfg.SET_CFG())
                    throw new Exception();

                MessageBox.Show("Koniguration gespeichert!");
            }
            catch(Exception)
            {
                MessageBox.Show("Fehler beim speichern der Konfiguration!");
            }
        }

        private void frm_Main_FormClosing(object sender, FormClosingEventArgs e)
        {
        }

        /// <summary>
        /// Gibt ein Array[][] mit den Logischen werder der GUI zurück
        /// </summary>
        /// <param name="I_O">Input (I) oder Output(O)</param>
        /// <returns>Lernparadigmen für das Netz</returns>
        public float[][] ValueTable(string I_O)
        {
            float[][] result = new float[this._dgv_vakuetable.Rows.Count][];

            // für jede Zeile
            for (int i = 0; i < this._dgv_vakuetable.Rows.Count; i++)
            {
                result[i] = new float[count(I_O)];
                int ct = 0;

                // Für jede Spalte
                for (int j = 0; j < this._dgv_vakuetable.Columns.Count; j++)
                    // Wenn die Spalte dem gewüschen typ entspricht (I/O)
                    if (this._dgv_vakuetable.Columns[j].Name.Substring(0, 1) == I_O)
                    {
                        result[i][ct] = (float)Convert.ToDouble(this._dgv_vakuetable.Rows[i].Cells[j].Value);
                        ct++;
                    }
            }

            return result;
        }

        /// <summary>
        /// Zählt die Eingaben bzw. Ausgaben
        /// </summary>
        /// <param name="I_O">Input (I) oder Output(O)</param>
        /// <returns>Anzahl der Spalten des betroffenen typs</returns>
        private int count(string I_O)
        {
            int ret = 0;

            // für jede spalte
            for (int i = 0; i < this._dgv_vakuetable.Columns.Count; i++)
                if (this._dgv_vakuetable.Columns[i].Name.Substring(0, 1) == I_O)
                    ret++;

            return ret;
        }

        /// <summary>
        /// Löscht eine Spalte anhand des namens
        /// </summary>
        /// <param name="name">Name der zu löschende Spalte</param>
        private void remove_by_name(string name)
        {
            // Für jede Spalte
            for (int i = 0; i < this._dgv_vakuetable.Columns.Count; i++)
                if (this._dgv_vakuetable.Columns[i].Name == name)
                {
                    this._dgv_vakuetable.Columns.RemoveAt(i);
                    return;
                }
        }

        /// <summary>
        /// Berechnet die Zeilen der GUI neu (Add, Remove, etc)
        /// </summary>
        /// <param name="add_combies">veraltet</param>
        private void recalc_rows(bool add_combies = true)
        {
            if (add_combies)
            {
                int current_sum = this._dgv_vakuetable.Rows.Count;
                int new_sum = Convert.ToInt32(Math.Pow(2, count("I")));

                // Zu viele Zeilen. Diese entfernen
                if (current_sum > new_sum)
                    for (int i = current_sum - 1; i >= new_sum; i--)
                        this._dgv_vakuetable.Rows.RemoveAt(i);
                else if (new_sum > current_sum)// Zu wenige zeilen, diese adden
                {
                    for (int i = current_sum; i < new_sum; i++)
                        this._dgv_vakuetable.Rows.Add(DecimalToBinary(0, count("I") + count("O")).ToArray());
                }

                // Binäres zählen, um den Standard zu erzeugen (jede kombination also)
                for (int j = 0; j < this._dgv_vakuetable.Rows.Count; j++)
                {
                    List<bool> values = DecimalToBinary(j, count("I"));
                    int n = 0;

                    // Für jede Spalte
                    for (int i = 0; i < this._dgv_vakuetable.Columns.Count; i++)
                        // Nur wenn es eine Eingabe-Spalte ist
                        if (this._dgv_vakuetable.Columns[i].Name.Substring(0, 1) == "I")
                        {
                            //this._dgv_vakuetable.Rows[j].Cells[i].ReadOnly = true;
                            this._dgv_vakuetable.Rows[j].Cells[i].Value = values[n++];
                        }
                }
            }
        }

        /// <summary>
        /// Konvertiert eine Dezimal-zahl zu einer Binären Zahl
        /// </summary>
        /// <param name="num">Zahl die zu Kovertiern ist</param>
        /// <param name="min_len">mindestlänge der Ausgabe</param>
        /// <returns>Liste mit bool, welche den Binärcode repräsentieren</returns>
        private List<bool> DecimalToBinary(int num, int min_len)
        {
            List<bool> result = new List<bool>();
            int rem = 0;

            while (num > 0)
            {
                rem = num % 2;
                num = num / 2;
                if (rem == 1)
                    result.Add(true);
                else
                    result.Add(false);
            }

            //Länge garantieren
            for (int i = result.Count; i < min_len; i++)
                result.Add(false);

            return result;
        }

        /// <summary>
        /// Fürgt eine Eingabe hinzu
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_inp_add_Click(object sender, EventArgs e)
        {
            DataGridViewCheckBoxColumn CB_COL;
            CB_COL = new DataGridViewCheckBoxColumn();
            CB_COL.HeaderText = "IN " + (count("I") + 1);
            CB_COL.Name = "I" + (count("I") + 1);
            CB_COL.AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;
            CB_COL.DisplayIndex = count("I");
            this._dgv_vakuetable.Columns.Add(CB_COL);

            recalc_rows();
        }

        /// <summary>
        /// Entfernt eine Eingabe
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_inp_rem_Click(object sender, EventArgs e)
        {
            if (count("I") > 1)
                remove_by_name("I" + count("I"));

            recalc_rows();
        }

        /// <summary>
        /// Fügt eine Ausgabe hinzu
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_out_add_Click(object sender, EventArgs e)
        {
            DataGridViewCheckBoxColumn CB_COL;
            CB_COL = new DataGridViewCheckBoxColumn();
            CB_COL.HeaderText = "OUT " + (count("O") + 1);
            CB_COL.Name = "O" + (count("O") + 1);
            CB_COL.AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;
            CB_COL.DisplayIndex = count("I") + count("O");
            this._dgv_vakuetable.Columns.Add(CB_COL);

            recalc_rows();
        }

        /// <summary>
        /// Löscht eine Ausgabe
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_out_rem_Click(object sender, EventArgs e)
        {
            if (count("O") > 1)
                remove_by_name("O" + count("O"));

            recalc_rows();
        }

        /// <summary>
        /// Erzeugt zufällige Aausgabe-werte für die Lernparadigmen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_random_Click(object sender, EventArgs e)
        {
            List<bool> rnd = new List<bool>();
            for (int i = 0; i < 100; i++)
                rnd.Add(i < this._nud_relation.Value);

            int out_anz = count("O");
            Random r = new Random();

            // Für jede zeile
            for (int i = 0; i < this._dgv_vakuetable.Rows.Count; i++)
                // Für jede Zelle der Ausgabe
                for (int j = 0; j < this._dgv_vakuetable.Rows[i].Cells.Count; j++)
                    // Für jede Ausgabe-Spalte (wir brauchen je eine bestimme)
                    for (int x = 1; x <= out_anz; x++)
                        if (this._dgv_vakuetable.Columns[j].Name == "O" + x)
                            this._dgv_vakuetable.Rows[i].Cells[j].Value = rnd[r.Next(0, 99)];// Wert setzten
        }

        /// <summary>
        /// Zeile löschen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_removerow_Click(object sender, EventArgs e)
        {
            try
            {
                for (int i = 0; i < this._dgv_vakuetable.SelectedRows.Count; i++)
                    this._dgv_vakuetable.Rows.Remove(this._dgv_vakuetable.SelectedRows[i]);
            }
            catch (Exception) { }
        }

        /// <summary>
        /// Automatische Eingabe-Werte wiederherstellen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_resetrows_Click(object sender, EventArgs e)
        {
            recalc_rows();
        }

        /// <summary>
        /// Wiedersprüch erzeugen. Zeigt alle dialoge an
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_wiedersprueche_Click(object sender, EventArgs e)
        {
            try
            {
                frm_wiedersprueche _DIAG = new frm_wiedersprueche();

                if (_DIAG.ShowDialog() == DialogResult.OK)
                {
                    this._dgv_vakuetable.Columns.Clear();

                    Random _R = new Random(Guid.NewGuid().GetHashCode());

                    if (System.Diagnostics.Debugger.IsAttached)
                        System.Diagnostics.Debugger.Break();

                    IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.DEBUG, "Starte Phase 1");
                    // Anwenden der Größeneinstellungen
                    for (int j = 0; j < _DIAG.Bits_p_AM; j++)
                    {
                        DataGridViewCheckBoxColumn CB_COL;
                        CB_COL = new DataGridViewCheckBoxColumn();
                        CB_COL.HeaderText = "OUT " + (count("O") + 1);
                        CB_COL.Name = "O" + (count("O") + 1);
                        CB_COL.AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;
                        CB_COL.DisplayIndex = count("I") + count("O");
                        this._dgv_vakuetable.Columns.Add(CB_COL);
                    }
                    IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.DEBUG, "Beende Phase 1");

                    // Eingabemuster-Array festlegen
                    _EinG_M = new bool[_DIAG.Anz_EM, _DIAG.Bits_p_EM];

                    IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.DEBUG, "Starte Phase 2");
                    // Eingabemuster erzeugen
                    // Für jedes Eingabmuster
                    for (int i = 0; i < _DIAG.Anz_EM; i++)
                    {
                        // Für jedes Bit
                        for (int j = 0; j < _DIAG.Bits_p_EM; j++)
                        {
                            IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.DEBUG, "Pahse 2 => i=" + i + "; j=" + j);

                            // Random bit setzten (bool)
                            _EinG_M[i, j] = _R.Next(0, 2) == 0;

                            // Beim ersten mal, die GUI aktualiseren
                            if (i == 0)
                            {
                                DataGridViewCheckBoxColumn CB_COL;
                                CB_COL = new DataGridViewCheckBoxColumn();
                                CB_COL.HeaderText = "IN " + (count("I") + 1);
                                CB_COL.Name = "I" + (count("I") + 1);
                                CB_COL.AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;
                                CB_COL.DisplayIndex = count("I");
                                this._dgv_vakuetable.Columns.Add(CB_COL);
                            }
                        }
                    }
                    IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.DEBUG, "Beende Phase 2");

                    // Jetzt werden die Eingabemuster angewendet
                    int out_anz = count("O");
                    IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.DEBUG, "Starte Phase 3");
                    for (int x = 1; x <= _DIAG.anz_MP; x++)
                    {
                        // Zufälliges Eingabemuster wählen
                        int ind = _R.Next(0, _DIAG.Anz_EM);
                        if (ind == _DIAG.Anz_EM)
                            ind = 0;

                        int sub_ind = 0;

                        // Zeile für das Muster in die DGV adden
                        this._dgv_vakuetable.Rows.Add(DecimalToBinary(0, count("I") + count("O")).ToArray());
                        int _ri = this._dgv_vakuetable.Rows.Count - 1;

                        // Für einbittiges Muster, den OUT-Index den gesetzten bit's bestimmen
                        int _RND_IND = _R.Next(0, out_anz) + 1;

                        // Für jede Zelle der neuen Zeile
                        for (int j = 0; j < this._dgv_vakuetable.Rows[_ri].Cells.Count; j++)
                        {
                            // Das Eingabemuster in die Eingabe übernehmen und der Ausgabe Random-Werte zuordnen
                            for (int n = 1; n <= out_anz; n++)
                            {
                                IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.DEBUG, "Phase 3 => x=" + x + "; j=" + j + "; n=" + n);

                                if (this._dgv_vakuetable.Columns[j].Name == "O" + n)
                                {
                                    // Ein einbittigs Muster?
                                    if (ind < _DIAG.anz_oneBit_AM)
                                        this._dgv_vakuetable.Rows[_ri].Cells[j].Value = n == _RND_IND;
                                    else
                                        this._dgv_vakuetable.Rows[_ri].Cells[j].Value = _R.Next(0, 2) == 0;
                                }
                                else
                                {
                                    if (this._dgv_vakuetable.Columns[j].Name == "I" + (sub_ind + 1))
                                        this._dgv_vakuetable.Rows[_ri].Cells[j].Value = _EinG_M[ind, sub_ind++];
                                }
                            }
                        }
                    }

                    // Gui neu berechnen (ohne default einstellung zu übernhemen) [veraltet]
                    recalc_rows(false);

                    // Netzgröße noch setzten
                    this._lv_Netzdimension.Items.Clear();
                    this._lv_Netzdimension.Items.Add(_DIAG.Bits_p_EM.ToString());
                    this._cb_s2.Checked = true;
                    this._nud_LR.Value = 1.00m;
                    this._nud_mom.Value = 0.00m;
                    this._nud_ll.Value = 70.0m;
                    this._nud_LR2.Value = 0.01m;
                    this._nud_mom2.Value = 0.9m;
                    this._nud_ll2.Value = 0.10m;
                    this._nud_alpha.Value = 2m;
                    this._cb_AF.SelectedIndex = 0;
                    this._cb_cycles.Checked = false;

                    this._b_relativehaeufigkeit.Enabled = true;
                }
            }
            catch(Exception ex)
            {
                IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.ERROR, ex.Message);
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// Ist die statistsiche auswertung der Wiedersprüche!
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_relativehaeufigkeit_Click(object sender, EventArgs e)
        {
            try
            {
                if (MessageBox.Show("Dafür muss NACH dem Lernvorgang eine Controller-Verbindung von dieser Anwendung aus hergestellt werden.\r\nIst der Lernvorgang bereits beendet worden und möchten Sie die Verbindung jetzt herstellen?", "", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                {
                    // Stelle Controller-Verbindung her, da hier netzausgben erfoderlich sind.
                    IVisual._SC.frm_Connect _tmp = new IVisual._SC.frm_Connect(!Environment.GetCommandLineArgs().Contains("-NOAD"));
                    if (_tmp.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                        return;

                    IVisual.I_Controller _ctrl = (IVisual.I_Controller)Activator.GetObject
                    (
                        typeof(IVisual.I_Controller),
                        "tcp://" + _tmp.IP.ToString() + ":" + _tmp.Port + "/_RM_Neuro_Controller"
                    );

                    if (_ctrl.GET_STATE() != System.Threading.ThreadState.Stopped)
                        MessageBox.Show("Der Lernvorgang läuft noch!");
                    else
                    {
                        //this._b_relativehaeufigkeit.Enabled = false;
                        frm_TextShow _TS = new frm_TextShow(_ctrl.CALC_Haeufigkeit(this._EinG_M));
                        _TS.ShowDialog();
                    }
                }
            }catch(Exception ex)
            {
                IVisual._SC.cls_LOG.WRITE_LOG_LINE(IVisual._SC.cls_LOG.LOGLEVEL.ERROR, ex.Message);
                MessageBox.Show("Nicht möglich!");
            }
        }

        /// <summary>
        /// Kontextmenü der LV für die netzgröße (Adden)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void neuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this._lv_Netzdimension.Items.Add("2");
        }

        /// <summary>
        /// Kontextmenü der LV für die netzgröße (Löschen)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void löschenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this._lv_Netzdimension.SelectedItems.Count != 1 || this._lv_Netzdimension.Items.Count < 1)
                return;

            this._lv_Netzdimension.SelectedItems[0].Remove();
        }

        /// <summary>
        /// Bricht die konfiguration ab
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmd_cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// startet den Autodiscover für die visualisierung
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmd_visual_autodiscover_Click(object sender, EventArgs e)
        {
            _AutoDiscovery_cli = new BackgroundWorker();
            _AutoDiscovery_cli.WorkerReportsProgress = true;
            _AutoDiscovery_cli.WorkerSupportsCancellation = true;

            svcAutoDiscoveryClient = new IVisual._SC.AutoDiscovery.cls_AutoDiscovery_Client(ref _AutoDiscovery_cli);
            svcAutoDiscoveryClient.AutoDiscoveryPort++;
            svcAutoDiscoveryClient.packetBytes = new byte[] { 0x2, 0x3, 0x4 };//Visual-Server
            _AutoDiscovery_cli.DoWork += new DoWorkEventHandler(svcAutoDiscoveryClient.Start);
            //_AutoDiscovery_cli.ProgressChanged += new ProgressChangedEventHandler(logWorkers_ProgressChanged);
            _AutoDiscovery_cli.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.AutoDiscovery_cli_RunWorkerCompleted);
            _AutoDiscovery_cli.RunWorkerAsync();

            this._pb_autodisc.Visible = true;
            this.cmd_visual_autodiscover.Enabled = false;
        }

        /// <summary>
        /// AD-beendet. Setzt ggf. Werte
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AutoDiscovery_cli_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this._pb_autodisc.Visible = false;
            this.cmd_visual_autodiscover.Enabled = true;

            if ((bool)e.Result)
            {
                this._tb_visu_IP.Text = IVisual._SC.cls_tools.try_reverse_resolve(svcAutoDiscoveryClient.ServerAddress);
                this._tb_visual_port.Text = svcAutoDiscoveryClient.ServerPort.ToString();
            }
        }

        /// <summary>
        /// Toggelt die Schranken-GUI elemente der stufe 2
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _cb_s2_CheckedChanged(object sender, EventArgs e)
        {
            this._nud_LR2.Enabled = this._cb_s2.Checked;
            this._nud_mom2.Enabled = this._cb_s2.Checked;
            this._nud_ll2.Enabled = this._cb_s2.Checked;
        }

        private void _cb_MAIL_Enabled_CheckedChanged(object sender, EventArgs e)
        {
            this._gB_MAIL.Enabled = this._cb_MAIL_Enabled.Checked;
        }

        private void _cb_MAIL_Auth_CheckedChanged(object sender, EventArgs e)
        {
            this._tb_MAIL_USN.Enabled = this._cb_MAIL_Auth.Checked;
            this._tb_MAIL_PW.Enabled = this._cb_MAIL_Auth.Checked;
        }
    }
}
